package com.sdyeda.readiot;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.alibaba.fastjson.JSON;
import com.sdyeda.readiot.api.CallApi;
import com.sdyeda.readiot.config.Setting;
import com.sdyeda.readiot.data.SetSave;
import com.sdyeda.readiot.fx.MainWindowController;
import com.sdyeda.readiot.fx.ReadDialogController;
import com.sdyeda.readiot.iotinfo.DtuInfo;
import com.sdyeda.readiot.iotinfo.IotData;
import com.sdyeda.readiot.iotinfo.IotInfo;
import com.sdyeda.readiot.iotinfo.JdbcIotInfo;
import com.sdyeda.readiot.iotinfo.ReadingInfo;
import com.sdyeda.readiot.tools.HexTools;

public class ReadDtuTaskService {
	Object lock = 0;

	private Socket socket = null;// = null;
	private OutputStream writer = null;// = new BufferedWriter(writer);
	private InputStream reader = null;

	int numiots = 0; // 传感器数
	int numsuccess = 0;

	private final Log log = LogFactory.getLog(this.getClass());

	void sleep(long t) {
		try {
			Thread.sleep(t);
		} catch (InterruptedException e) {
		}
	}

	public void ReadComStepByStep(IotInfo iotinfo, String command, ReadDialogController controller) {
		// 读写缓冲区
		// SendBuff sendBuff = new SendBuff();
		// ReceiveBuff receiveBuff = new ReceiveBuff();
		// receiveBuff.set
		@SuppressWarnings("unchecked")
		Map<String, SetSave> saves = (Map<String, SetSave>) Setting.Get(Setting.IOTTYPE);
		SetSave save = saves.get(iotinfo.getType());

		controller.clearInfo();
		controller.setInfo(0, "开始...", -1);
		sleep(100);
		controller.setInfo(0, "第一步：连接端口。", -1);
		sleep(300);

		// Step1 打开串口
		// System.out.println(iotinfo.getIp());
		// System.out.println(iotinfo.getPort());
		if (!open(new DtuInfo(iotinfo.getIp(), iotinfo.getPort()))) {
			// log.error(com + "打开失败！");
			controller.setInfo(0, iotinfo.getIp() + "1连接失败，异常终止！", -1);
			return;
		}
		controller.setInfo(1.0 / 6, iotinfo.getIp() + "连接成功。", -1);
		sleep(300);

		controller.setInfo(1.0 / 6, "第二步：初始化发送缓冲区。", -1);
		sleep(300);
		// Setp2 初始化发送缓冲区
		/*
		 * if(command == (byte)0x80) { sendBuff.setIdonly(iotinfo.getIotid()); } else {
		 * sendBuff.setId(iotinfo.getIotid()); } sendBuff.setCommand(command); //不可忘记
		 */
		byte[] sendbuff = CallApi.MakeSender(save.getJarname(), save.getClassname(), iotinfo.getIotid(), command);
		if (sendbuff == null) {
			controller.setInfo(1.0 / 6, "发送缓冲区初始化失败！", -1);
			return;
		}

		controller.setInfo(2.0 / 6, "发送缓冲区初始化成功。", -1);
		controller.setInfo(2.0 / 6, "发送缓冲区：" + HexTools.bytesToHex(sendbuff), -1);
		// sleep(300);

		controller.setInfo(2.0 / 6, "第三步：发送数据指令。", -1);
		// Step3 发送指令数据
		if (!write(sendbuff)) {
			// log.error("发送指令失败");
			controller.setInfo(2.0 / 6, "数据指令发送失败，异常终止！", -1);
			close();
			return;
		}

		controller.setInfo(3.0 / 6, "发送数据指令成功！", -1);
		// sleep(300);

		controller.setInfo(3.0 / 6, "第四步：读取数据。", -1);
		// Step4 读取数据
		byte[] recive = read(2000l);
		// int n = read(receiveBuff.getBuff(), 1);
		// log.info("读取数据"+n + "字节：" + receiveBuff.toString());
		if (recive == null) {
			controller.setInfo(3.0 / 6, "数据读取失败，异常终止！", -1);
			// log.error("读取传感器失败");
			close();
			return;
		}
		// close(comPort);

		// receiveBuff.setReadnums(n);
		controller.setInfo(4.0 / 6, "读取数据成功，收到" + recive.length + "字节数据。", -1);
		controller.setInfo(4.0 / 6, "数据：" + HexTools.bytesToHex(recive), -1);
		// sleep(300);

		controller.setInfo(4.0 / 6, "第五步：解析数据。", -1);
		// Step5 解析数据
		String jsonData = CallApi.DecRecive(save.getJarname(), save.getClassname(), recive);
		if (jsonData == null) {

			controller.setInfo(4.0 / 6, "数据解析失败，异常终止！", -1);
			// log.error("解析传感器数据失败");
			close();
			return;
		}
		controller.setInfo(5.0 / 6, "解析数据成功。", -1);
		if (command.equals("read")) { // 调零不输出
			controller.setInfo(5.0 / 6, "数据：" + jsonData, -1);
		}
		sleep(500);

		controller.setInfo(5.0 / 6, "第六步：关闭端口。", -1);
		close();
		sleep(300);
		controller.setInfo(6.0 / 6, "关闭端口成功。", -1);
		controller.setInfo(1, "结束。", -1);
	}

	public Integer ReadCom(DtuInfo dtu, List<IotInfo> listIotinfo) {

		// 读取重试次数
		int retrytime = (int) Setting.setting.get(Setting.RETRYTIMES);

		// SendBuff sendBuff = new SendBuff();
		// ReceiveBuff receiveBuff = new ReceiveBuff();
		// 设备接口程序
		@SuppressWarnings("unchecked")
		Map<String, SetSave> saves = (Map<String, SetSave>) Setting.Get(Setting.IOTTYPE);

		numiots = listIotinfo.size(); // 传感器数
		numsuccess = 0;

		if (!open(dtu)) {
			log.error(dtu.getIp() + "打开失败！");
			return 0;
		}

		listIotinfo.forEach(item -> {

			// sendBuff.setId("28DD220813000001");
			SetSave save = saves.get(item.getType());

			IotData iotdata = null;
			boolean success = false;

			/*
			 * if (item.getType().equals("5")) { //雨量计 sendBuff.setRainId(item.getIotid());
			 * } else { sendBuff.setId(item.getIotid()); }
			 */
			// item.getType();

			// receiveBuff.setIotdata(new IotData(item));

			// Setting.RefreshIotTableList(receiveBuff.getIotdata());
			// log.info(sendBuff.toString());
			// retrytime = 3;
			// 调用接口生成发送数组 jarname，classname与ID
			byte[] sendbuff = CallApi.MakeSender(save.getJarname(), save.getClassname(), item.getId());
			if (sendbuff != null) {

				int i = 1;
				for (i = 1; i <= retrytime; i++) {
					Long delay = 2000l + i * 3000l;
					// 发送
					if (!write(sendbuff)) {
						break;
					}
					// 读取数据
					byte[] recive = read(delay);
					if (recive == null) {
						continue;
					}

					// 调用接口解析收到数组
					String jsonData = CallApi.DecRecive(save.getJarname(), save.getClassname(), recive);
					if (jsonData == null) {
						continue;
					} else {
						iotdata = JSON.parseObject(jsonData, IotData.class);
						if (iotdata == null) {
							continue;
						}
						iotdata.setReadtimes(i);
						success = true;
						break;
					}
				}

				if (success) {
					log.info(dtu.getIp() + "-- " + item.getId() + " 读取成功！");

					if (JdbcIotInfo.write(iotdata) > 0) {
						log.info(dtu.getIp() + "-- " + item.getId() + " 数据存储成功！");
						numsuccess += 1;
					} else {
						log.error(dtu.getIp() + "--" + item.getId() + " 数据存储失败!");
					}
				} else {
					log.error(dtu.getIp() + "-- " + item.getId() + " 读取失败！");
				}
			} else {
				log.error(dtu.getIp() + "-- " + item.getId() + " 读取失败！");
			}
			// log.info(JSONObject.toJSONString( receiveBuff.getIotdata()));
			// 写Setting //设置线程锁
			synchronized (lock) {
				((ReadingInfo) Setting.Get(Setting.READINGINFO)).setIotData(iotdata);
				MainWindowController controller = (MainWindowController) Setting.Get(Setting.MAINWINDOW_CONTROLLER);
				if (controller != null) {
					controller.refushList();
				}
			}

		});
		log.info(dtu.getIp() + "总计" + numiots + "个传感器,成功读取" + numsuccess + "个！");

		close();

		return numsuccess;
	}

	/*
	 * boolean readiot(SendBuff sendBuff, ReceiveBuff receiveBuff, int times) {
	 * 
	 * if (!write(sendBuff.getBuff(), sendBuff.getSize())) { log.error("发送指令失败");
	 * return false; } // log.info("发送数据" + sendBuff.toHexString() + "成功！");
	 * 
	 * receiveBuff.clearbuff();
	 * 
	 * // while(comPort.bytesAvailable>0){//循环读取所有的返回数据。如果可读取数据长度为0或-1，则停止读取 //
	 * 失败则增加读取时间
	 * 
	 * if (sendBuff.getBuff()[2] == (byte) 0x1B) { // 雨量计历史数据需要增加时间 times = times *
	 * times + 8; } int n = read(receiveBuff.getBuff(), times);
	 * 
	 * // log.info("读取数据"+n + "字节：" + receiveBuff.toString()); if (n <= 0) { //
	 * log.error("读取传感器失败"); return false; }
	 * 
	 * receiveBuff.setReadnums(n);
	 * 
	 * if (!receiveBuff.Analysis()) { // log.error("解析传感器数据失败"); return false; }
	 * 
	 * return true; }
	 */

	// 写
	boolean write(byte[] buf) {
		// System.out.println(writer);
		if (writer == null) {
			return false;
		}
		try {
			writer.write(buf);
			writer.flush();
			Thread.sleep(100);// 休眠0.1秒，等待下位机返回数据。如果不休眠直接读取，有可能无法成功读到数据

			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	// 现场重点测试此函数
	byte[] read(Long delay) {
		int availnum = 0; // 准备好数据尺寸
		int readnum = 0; // 读取尺寸
		int sumnum = 0; // 累计读取尺寸
		byte[] readbuf = null;
		byte[] buf = new byte[1024];
		if (reader == null) {
			return null;
		}
		try {
			// 根据次数设置读取时间，第一次2秒，每次增加1秒-----------经测试，2秒时间比较合适
			long now = new Date().getTime();
			while ((new Date()).getTime() - now < delay) {
				availnum = reader.available();
				if (availnum < 0)
					break; // 无数据
				if (availnum == 0)
					continue;// 数据未准备好

				readbuf = new byte[availnum];
				readnum = reader.read(readbuf);// readBytes(readbuf, availnum);
				// System.out.println("---"+readnum+" time:"+times);
				if (readnum > 0) {
					System.arraycopy(readbuf, 0, buf, sumnum, readnum);
					sumnum += readnum;
				}
				Thread.sleep(100);
			}

		} catch (Exception e) {
			return null;
		}
		byte[] result = new byte[sumnum];
		System.arraycopy(buf, 0, result, 0, sumnum);
		return result;
	}

	boolean open(DtuInfo dtu) {
		try {
			// 连接 服务器
			// timeout =1s
			socket = new Socket();
			socket.connect(new InetSocketAddress(dtu.getIp(), dtu.getPort()), 1000);
			// System.out.println(dtu.getIp());
			// System.out.println(dtu.getIp());
			writer = socket.getOutputStream();
			reader = socket.getInputStream();
			// log.info(Setting.LOG_CONNECT_SUCCESS); // 连接成功
			return true;

		} catch (Exception e) {
			return false;
			// log.error(Setting.LOG_CONNECT_FAILED + e);
		}
	}

	boolean close() {

		try {
			if (writer != null) {
				writer.close();
				writer = null;
			}
			if (reader != null) {
				reader.close();
				reader = null;
			}
			if (socket != null) {
				socket.close();
				socket = null;
			}
			return true;
			// log.info(Setting.LOG_CONNECT_CLOSE_SUCCESS);
		} catch (Exception e) {
			// System.out.println(e.toString());
			return false;
			// log.error(Setting.LOG_CONNECT_CLOSE_FAILED);
		}
	}
}
